// Copyright Druid Mechanics


#include "AbilitySystem/AsyncTasks/WaitCooldownChange.h"
#include "AbilitySystemComponent.h"
#include "GameplayTagContainer.h"

UWaitCooldownChange* UWaitCooldownChange::WaitForCooldownChange(UAbilitySystemComponent* AbilitySystemComponent,
                                                                const FGameplayTag& InCooldownTag)
{
	UWaitCooldownChange* WaitCooldownChange = NewObject<UWaitCooldownChange>();
	WaitCooldownChange->ASC = AbilitySystemComponent;
	WaitCooldownChange->CooldownTag = InCooldownTag;
	/**
	 * IsValid(TestObjPtr): 如果最终继承自UObject的指针是否实际存在的，存在则返回true。
	 * TestPtr/TestVar.IsValid(): 如果最终不继承自UObject的指针是否实际存在的，存在则返回true。
	 */
	if (!IsValid(AbilitySystemComponent) || !InCooldownTag.IsValid())
	{
		WaitCooldownChange->EndTask();
		return nullptr;
	}
	/**
	 * To know when a cooldown has ended (Cooldown Tag has been removed)
	 */
	AbilitySystemComponent->RegisterGameplayTagEvent(InCooldownTag, EGameplayTagEventType::NewOrRemoved).AddUObject(
		WaitCooldownChange, &UWaitCooldownChange::CooldownTagChanged);
	/**
	 * To know when a cooldown effect has been applied
	 */
	/**
	 * OnActiveGameplayEffectAddedDelegateToSelf: 每当一个基于Duration的GE被添加时，在客户端和服务器都调用。
	 */
	AbilitySystemComponent->OnActiveGameplayEffectAddedDelegateToSelf.AddUObject(
		WaitCooldownChange, &UWaitCooldownChange::OnActiveEffectAdded);
	return WaitCooldownChange;
}

void UWaitCooldownChange::EndTask()
{
	if (!IsValid(ASC))
	{
		return;
	}
	ASC->RegisterGameplayTagEvent(CooldownTag, EGameplayTagEventType::NewOrRemoved).RemoveAll(this);
	/**
	 * SetReadyToDestroy: 当行为完成时调用，它能确保行为免费删除，并且从游戏实例中取消注册。
	 */
	SetReadyToDestroy();
	/**
	 * MarkAsGarbage: 标记对象为垃圾，可回收。
	 */
	MarkAsGarbage();
}

void UWaitCooldownChange::CooldownTagChanged(const FGameplayTag InCooldownTag, int32 NewCount)
{
	if (NewCount == 0)
	{
		CooldownEnd.Broadcast(0.f);
	}
}

void UWaitCooldownChange::OnActiveEffectAdded(UAbilitySystemComponent* TargetASC,
                                              const FGameplayEffectSpec& SpecApplied,
                                              FActiveGameplayEffectHandle ActiveEffectHandle)
{
	FGameplayTagContainer AssetTags;
	SpecApplied.GetAllAssetTags(AssetTags);

	FGameplayTagContainer GrantedTags;
	SpecApplied.GetAllGrantedTags(GrantedTags);

	if (AssetTags.HasTagExact(CooldownTag) || GrantedTags.HasTagExact(CooldownTag))
	{
		/**
		 * FGameplayEffectQuery::MakeQuery_MatchAnyOwningTags: 创建一个效果查询，若给定标签与某个激活ActiveGameplayEffect的所属标签之间存在任何共同标签，则该查询将匹配成功。 
		 */
		/**
		 * GetSingleTagContainer: 返回仅有这个标签的标签容器。
		 */
		FGameplayEffectQuery GameplayEffectQuery = FGameplayEffectQuery::MakeQuery_MatchAnyOwningTags(
			CooldownTag.GetSingleTagContainer());
		/**
		 * GetActiveEffectsTimeRemaining: 获取匹配参数的所有GE的剩余时间。
		 */
		TArray<float> TimesRemaining = ASC->GetActiveEffectsTimeRemaining(GameplayEffectQuery);
		if (TimesRemaining.Num() > 0)
		{
			float TimeRemaining = TimesRemaining[0];
			for(int32 i = 0; i < TimesRemaining.Num(); i ++)
			{
				if(TimesRemaining[i] > TimeRemaining)
				{
					TimeRemaining = TimesRemaining[i];
				}
			}
			CooldownStart.Broadcast(TimeRemaining);
		}
	}
}
